package com.ljq.rpc.client.config;

import com.alibaba.fastjson.util.ParameterizedTypeImpl;
import com.ljq.rpc.annotations.ClientComponent;
import com.ljq.rpc.client.handler.NettyClientHandler;
import com.ljq.rpc.client.utils.FutureFactory;
import com.ljq.rpc.codec.JSONDecoder;
import com.ljq.rpc.codec.JSONEncoder;
import com.ljq.rpc.common.enums.MsgType;
import com.ljq.rpc.common.pojo.Request;
import com.ljq.rpc.common.pojo.Response;
import com.ljq.rpc.common.pojo.RpcFuture;
import com.ljq.rpc.common.protocol.dubboProtocol;
import com.ljq.rpc.controller.controller;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.concurrent.DefaultPromise;


import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.Arrays;

@ClientComponent
public class NettyClient {

    private final ClientConfig clientConfig;

    private ChannelFuture channelFuture;

    public NettyClient(ClientConfig clientConfig) throws InterruptedException {
        this.clientConfig = clientConfig;
        initClient(clientConfig);
    }

    //返回一个代理对象
    public Object getBean(final Class<?> serviceClass) throws InterruptedException {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        return Proxy.newProxyInstance(classLoader,new Class<?>[]{serviceClass},((proxy, method, args) -> {
            return request(serviceClass.getSimpleName(),method.getName(),args,method.getParameterTypes());
        }));
    }


    private void initClient(ClientConfig clientConfig) throws InterruptedException {
        //创建EventLoopGroup
        NioEventLoopGroup group = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();

        bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY,true)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ChannelPipeline pipeline = ch.pipeline();
                        pipeline.addLast(new JSONDecoder())
                                .addLast(new JSONEncoder())
                                .addLast(new NettyClientHandler());
                    }
                });
        channelFuture = bootstrap.connect(clientConfig.getHost(), clientConfig.getPort()).sync();
    }

    public Object request(String serviceName,String methodName, Object[] paras, Class<?>[] parasClass) throws Exception {
        //构造协议包
        RpcFuture<Response> future = new RpcFuture<>(new DefaultPromise<>(new DefaultEventLoop()));
        Long REQUEST_ID = FutureFactory.put(future);
        for(Object o:paras){
            System.out.println(o.getClass().getSimpleName());
            Class<?> aClass = Class.forName(o.getClass().getSimpleName()+".class");
        }
        dubboProtocol<Request> dubboProtocol = new dubboProtocol<Request>(REQUEST_ID,MsgType.REQUEST.getTypeID(),new Request(serviceName,methodName,paras,parasClass));
        channelFuture.channel().writeAndFlush(dubboProtocol);
        return future.getPromise().get().getContent();
    }


}
